/*****************************************************************************/
/*!	\file		PrintView.c
 *	\brief 		C Source code file for the PIS10 Stack Example
	\par        Dalian Yunxing Tech Co., Ltd.

				Dalian, China
				Phone   : +86 (411) 8825 4852
				Email   : yx@yunxing.tech
 */
/*****************************************************************************/

#include <stdlib.h>
#include "PrintView.h"
#include <string.h>

/******************************************************************************
*       PrintServerFullView Function Definition
******************************************************************************/
/*!  \brief         This function prints the Server Menu and Data View to the screen
 *
 *   \ingroup       View Function
 *
 *   \param[in]     Var     DESC
 *
 *   \return        N/A
 ******************************************************************************/
void PrintServerFullView(void)
{
	ClearScreen();
	PrintServerHeader();
	PrintDataView();
	PrintErrorString();
	PrintServerMenuView();
	printf("Select a Command: ");
    fflush(stdout); // Will now print everything in the stdout buffer
}


/******************************************************************************
*       PrintClientFullView Function Definition
******************************************************************************/
/*!  \brief         This function prints the Client Menu and Data View to the screen
 *
 *   \ingroup       View Function
 *
 *   \param[in]     Var     DESC
 *
 *   \return        N/A
 ******************************************************************************/
void PrintClientFullView(void)
{
	ClearScreen();
	PrintClientHeader();
	PrintDataView();
	PrintErrorString();
	PrintClientMenuView();
	printf("Select a Command: ");
	fflush(stdout); // Will now print everything in the stdout buffer
}


/******************************************************************************
*       PrintServerSubscriptionFullView Function Definition
******************************************************************************/
/*!  \brief         This function prints the Server Subscription Menu and Data View to the screen
 *
 *   \ingroup       View Function
 *
 *   \param[in]     Var     DESC
 *
 *   \return        N/A
 ******************************************************************************/
void PrintServerSubscriptionFullView(void)
{
	ClearScreen();
	PrintServerSubscriptionHeader();
	PrintServerSubscriptionDataView();
	PrintErrorString();
	PrintServerSubscriptionMenuView();
	printf("Select a Command: ");
    fflush(stdout); // Will now print everything in the stdout buffer
}


/******************************************************************************
*       PrintServerHeader Function Definition
******************************************************************************/
/*!  \brief         This function prints the Server Header to the screen
 *
 *   \ingroup       View Function
 *
 *   \param[in]     Var     DESC
 *
 *   \return        N/A
 ******************************************************************************/
void PrintServerHeader(void)
{
	printf("----------------------------------------------------------------------------\n");
	printf("IEC61850 Server Example from yunxing.tech \nPIS10: %s\n", IEC61850_GetLibraryVersion());
	printf("----------------------------------------------------------------------------\n");
}

/******************************************************************************
*       PrintClientHeader Function Definition
******************************************************************************/
/*!  \brief         This function prints the Client Header to the screen
 *
 *   \ingroup       View Function
 *
 *   \param[in]     Var     DESC
 *
 *   \return        N/A
 ******************************************************************************/
void PrintClientHeader(void)
{
	printf("----------------------------------------------------------------------------\n");
	printf("IEC61850 Client Example from yunxing.tech \nPIS10: %s\n", IEC61850_GetLibraryVersion());
	printf("----------------------------------------------------------------------------\n");
}

/******************************************************************************
*       PrintServerSubscriptionHeader Function Definition
******************************************************************************/
/*!  \brief         This function prints the Server Subscription Header to the screen
 *
 *   \ingroup       View Function
 *
 *   \param[in]     Var     DESC
 *
 *   \return        N/A
 ******************************************************************************/
void PrintServerSubscriptionHeader(void)
{
	printf("----------------------------------------------------------------------------\n");
	printf("IEC61850 Server Subscription Example from yunxing.tech \nPIS10: %s\n", IEC61850_GetLibraryVersion());
	printf("----------------------------------------------------------------------------\n");
}

/******************************************************************************
*       PrintDataView Function Definition
******************************************************************************/
/*!  \brief         This function prints the Data View to the screen
 *
 *   \ingroup       View Function
 *
 *   \param[in]     Var     DESC
 *
 *   \return        N/A
 ******************************************************************************/
void PrintDataView(void)
{
	Integer8 i = 0; //Iterator Variable for the for loops

	printf("=================== IEC61850 Data ==========================================\n");

	printf("CSWI:\t CtlVal: %s\t StVal: %s\n",BooleanToString(GetCSWICtlVal()), DBPosToString(GetCSWIStVal()));    //Print CSWI Data
	printf("GGIO:\t CtlVal: %s\t StVal: %s\n",BooleanToString(GetGGIOCtlVal()), BooleanToString(GetGGIOCtlVal())); //Print GGIO Data
	printf("\n"); //new line for formating


#ifdef __PARADIGM__

	//Print MMXU Data
	printf("MMXU:\t PhsA$Mag$i: %ld\t ", GetMMXUPhsAMagi());  //Integer32 on beck is a long int so %ld is needed
    printf("PhsB$Mag$i: %ld\t ", GetMMXUPhsBMagi());
    printf("PhsC$Mag$i: %ld\n",GetMMXUPhsCMagi());
	printf("\n"); //new line for formating

	(void)i;

	/* We do not support Floating point on BECK devices
	 * Therefore we only add the CrvPts array if this
	 * is not being compiled for BECK devices
	 * */
#else

	//Print MMXU Data
	printf("MMXU:\t PhsA$Mag$i: %d\t ", GetMMXUPhsAMagi());
	printf("PhsB$Mag$i: %d\t ", GetMMXUPhsBMagi());
	printf("PhsC$Mag$i: %d\n",GetMMXUPhsCMagi());
	printf("\n"); //new line for formating

	/* Print PDIF DATA xVal array */
	printf("PDIF:\t xVal = { ");

	for(i=0; i <SIZE_OF_PDIF_ARRAY-1; i++)
	{
		printf("%2.2f, ", GetPDIFCrvPts(i).xVal);
	}
	printf("%3.2f }\n", GetPDIFCrvPts(SIZE_OF_PDIF_ARRAY-1).xVal); //Print the last element in the array with the closing bracket and new line

	/* Print PDIF DATA yVal array */
	printf("PDIF:\t yVal = { ");

	for(i=0; i <SIZE_OF_PDIF_ARRAY-1; i++)
	{
		printf("%3.2f, ", GetPDIFCrvPts(i).yVal);
	}
	printf("%2.2f }\n", GetPDIFCrvPts(SIZE_OF_PDIF_ARRAY-1).yVal); //Print the last element in the array with the closing bracket and new line

	printf("\n"); //new line for formating

	/* Print SV data TnsSv*/
	printf("TTNS:\t TnsSv1$Mag$f: %3.2f   ", GetTTNSTnsSv1Magf());
	printf("TnsSv2$Mag$f: %3.2f   ", GetTTNSTnsSv2Magf());
	printf("TnsSv3$Mag$f: %3.2f\n", GetTTNSTnsSv3Magf());
	printf("\n"); //new line for formating

	/* Print SettingGroup data*/
	printf("IARC:\t MaxNumRcd$setVal: %d   ", GetMaxNumRcd());
	printf("OpMod$setVal: %d   ", GetOpMod());
	printf("MemFull$setVal: %d\n", GetMemFull());
	printf("\n"); //new line for formating
#endif
}


/******************************************************************************
*       PrintServerSubscriptionDataView Function Definition
******************************************************************************/
/*!  \brief         This function prints the Data View for the server subscription to the screen, this is cut down from the main view for clarity
 *
 *   \ingroup       View Function
 *
 *   \param[in]     Var     DESC
 *
 *   \return        N/A
 ******************************************************************************/
void PrintServerSubscriptionDataView(void)
{
	printf("=================== IEC61850 Data ==========================================\n");

	printf("CSWI:\t StVal: %s\n", DBPosToString(GetCSWIStVal()));    //Print CSWI Data
	printf("GGIO:\t StVal: %s\n", BooleanToString(GetGGIOStVal())); //Print GGIO Data
	printf("\n"); //new line for formating
}

/******************************************************************************
*       PrintErrorSrtring Function Definition
******************************************************************************/
/*!  \brief         This function prints the Menu View to the screen
 *
 *   \ingroup       View Function
 *
 *   \param[in]     Var     DESC
 *
 *   \return        N/A
 ******************************************************************************/
void PrintErrorString(void)
{
	printf("=================== Last Error =============================================\n");
	if(GetErrorString()[0] == 0)
	{
		printf("NONE\n");
	}
	else
	{
		printf("%s\n", GetErrorString());
	}

}


/******************************************************************************
*       PrintServerMenuView Function Definition
******************************************************************************/
/*!  \brief         This function prints the Server Menu View to the screen
 *
 *   \ingroup       View Function
 *
 *   \param[in]     Var     DESC
 *
 *   \return        N/A
 ******************************************************************************/
void PrintServerMenuView(void)
{
	printf("=================== IEC61850 Command Menu ==================================\n");
	printf("1) Update PhsA Mag i \t DAID: {3,0,0,0,0}\n");
	printf("2) Update PhsB Mag i \t DAID: {4,0,0,0,0}\n");
	printf("3) Update PhsC Mag i \t DAID: {5,0,0,0,0}\n");

	/* We do not support Floating point on BECK devices
	 * Therefore we only add the CrvPts array if this
	 * is not being compiled for BECK devices
	 * */
#ifndef __PARADIGM__
	printf("4) Update crvPts Xval \t DAID: {6,0,0,0,0} \n");
	printf("5) Update crvPts Yval\n");
#endif
	printf("6) Update Anin1 Mag f \t DAID: {7,0,0,0,0}\n");
	printf("7) Update Anin2 Mag f \t DAID: {7,0,0,0,1}\n");
	printf("8) Update Anin3 Mag f \t DAID: {7,0,0,0,2}\n");

	printf("X) To Exit\n");
	printf("============================================================================\n");

}

/******************************************************************************
*       PrintClientMenuView Function Definition
******************************************************************************/
/*!  \brief         This function prints the Client Menu View to the screen
 *
 *   \ingroup       View Function
 *
 *   \param[in]     Var     DESC
 *
 *   \return        N/A
 ******************************************************************************/
void PrintClientMenuView(void)
{
	printf("=================== IEC61850 Command Menu ==================================\n");
	printf("1) Select & Operate CSWI  DAID: {1,1,0,0,0}\n");
	printf("2) Operate GGIO \t  DAID: {2,1,0,0,0}\n");
	printf("3) Get Connected Server List\n");
	printf("4) File Operate\n");
	printf("5) SettingGroup Operate\n");
	printf("6) Log Operate\n");
	printf("X) To Exit\n");
	printf("============================================================================\n");

}


/******************************************************************************
*       PrintServerSubscriptionMenuView Function Definition
******************************************************************************/
/*!  \brief         This function prints the Server Subscription Menu View to the screen
 *
 *   \ingroup       View Function
 *
 *   \param[in]     Var     DESC
 *
 *   \return        N/A
 ******************************************************************************/
void PrintServerSubscriptionMenuView(void)
{
	printf("=================== IEC61850 Command Menu ==================================\n");
	printf("X) To Exit\n");
	printf("============================================================================\n");

}

/******************************************************************************
*       BooleanToString Function Definition
******************************************************************************/
/*!  \brief         This function Returns a Cstring representation of a boolean (True or False)
 *
 *   \ingroup       View Function
 *
 *   \param[in]     Var     DESC
 *
 *   \return        False if inBool is 0,
 *   \return        otherwise True
 ******************************************************************************/
const char* BooleanToString(Boolean inBool)
{
	const char * returnString;
	static const char * const boolStrings[] ={"True", "False" };

	if(inBool == FALSE)
	{
		returnString = boolStrings[1]; //Set returnString to False
	}
	else
	{
		returnString = boolStrings[0]; //Set returnString to True
	}

	return returnString;
}


/******************************************************************************
*       DBPosToString Function Definition
******************************************************************************/
/*!  \brief         This function Returns a Cstring representation of an enum DbPosValues
 *
 *   \ingroup       View Function
 *
 *   \param[in]     inDBPosVal     An enum DbPosValues that will be used to generate the string value
 *
 *   \return        "INTERMEDIATE" if inDBPosVal is DBPOS_INTERMEDIATE
 *   \return        "OFF" if inDBPosVal is DBPOS_OFF,
 *   \return        "ON" if inDBPosVal is DBPOS_ON,
 *   \return        "BAD" if inDBPosVal is DBPOS_BAD,
 *   \return        otherwise NULL pointer
 ******************************************************************************/
const char* DBPosToString(enum DbPosValues inDBPosVal)
{
	const char * returnString;
	static const char * const dbPosStrings[] ={"INTERMEDIATE", "OFF", "ON", "BAD"};

	switch(inDBPosVal)
	{
	case DBPOS_INTERMEDIATE:
		returnString = dbPosStrings[0];
		break;
	case DBPOS_OFF:
		returnString = dbPosStrings[1];
		break;
	case DBPOS_ON:
		returnString = dbPosStrings[2];
		break;
	case DBPOS_BAD:
		returnString = dbPosStrings[3];
		break;
	default:
		returnString = NULL;
		break;
	}

	return returnString;
}


/******************************************************************************
*       ClearScreen Function Definition
******************************************************************************/
/*!  \brief         This function Clears the screen
 *
 *   \ingroup       View Function
 *
 *   \param[in]     N/A
 *
 *   \return        N/A
 ******************************************************************************/
void ClearScreen(void)
{
	/* There is no CLS or clear command on beck RTOS so only execute if this is not a BECK Device*/

#ifndef __PARADIGM__
	//Simple way to clear the screen
	if (system("CLS")) system("clear");
#else
	printf("\n\n\n\n\n\n\n\n\n\n"); //on Beck just push the old screen up by 10 lines
#endif

#ifndef WIN32
   printf("\033[2J\033[1;1H");  //Clear Screen ANSI (not supported on windows)
#endif


}

void PrintFileMenuView(void)
{
	printf("================ File Menu ================\n");
	printf("1) GetFile\n");
	printf("2) SetFile\n");
	printf("3) DeleteFile\n");
	printf("4) GetFileAttributeValues\n");
	printf("0) Return to main menu\n");
}

void PrintSettingGroupMenuView(void)
{
	printf("============ SettingGroup Menu ============\n");
	printf("1) GetSGValue\n");
	printf("2) SelectActiveSG\n");
	printf("3) SelectEditSG\n");
	printf("4) SetEditSGValue\n");
	printf("5) ConfirmEditSGValues\n");
	printf("6) GetSGCBValues\n");
	printf("0) Return to main menu\n");
}

void PrintLogMenuView(void)
{
	printf("================ Log Menu ================\n");
	printf("1) QueryLogByTime\n");
	printf("2) Query log after id\n");
	printf("3) Query log statue\n");
	printf("0) Return to main menu\n");
}

void printTimeStamp(struct IEC61850_TimeStamp* pTimeStamp)
{
	if (pTimeStamp != NULL)
	{
		struct IEC61850_DateTime T = { 0 };
		IEC61850_GetDateFromIEC61850Time(&T, pTimeStamp);

		printf("[%d/%d/%d %d:%d:%d.%d]", T.year, T.month, T.tm_mday, T.tm_hour, T.tm_min, T.tm_sec, T.tm_uSec);
	}
}
void printLogVals(struct IEC61850_LogEntries* ptLogEntries)
{
	if (ptLogEntries == NULL)
	{
		printf("Log Val list Error\n");
	}
	else
	{
		Unsigned64 enteryID = 0;
		for (unsigned int i = 0; i < ptLogEntries->numberOfEntries; i++)
		{
			printf("No. %d:\n", i + 1);
			enteryID = (Unsigned64)ptLogEntries->logEntries[i].entryID[0] * 0x100000000000000
				+ (Unsigned64)ptLogEntries->logEntries[i].entryID[1] * 0x1000000000000
				+ (Unsigned64)ptLogEntries->logEntries[i].entryID[2] * 0x10000000000
				+ (Unsigned64)ptLogEntries->logEntries[i].entryID[3] * 0x100000000
				+ (Unsigned64)ptLogEntries->logEntries[i].entryID[4] * 0x1000000
				+ (Unsigned64)ptLogEntries->logEntries[i].entryID[5] * 0x10000
				+ (Unsigned64)ptLogEntries->logEntries[i].entryID[6] * 0x100
				+ ptLogEntries->logEntries[i].entryID[7];
			printf("  Log EnterID:      [%llu]\n", enteryID);
			printf("  Log EnterTime:    [");
			printTimeStamp(&ptLogEntries->logEntries[i].entryTime);

			printf("]\n  Log EnterData:\n");
			for (unsigned int j = 0; j < ptLogEntries->logEntries[i].numberOfLogEntryData; j++)
			{
				printf("\tData Ref:      [%s]\n", ptLogEntries->logEntries[i].logEntryData[j].DataRef);
				printf("\tData FC:       [%s]\n", ptLogEntries->logEntries[i].logEntryData[j].sFC);
				printf("\tData value:\n");
				printDAVal(&ptLogEntries->logEntries[i].logEntryData[j].logValue, 6);
				if (ptLogEntries->logEntries[i].logEntryData[j].reasconCode == IEC61850_DATA_CHANGE)
				{
					printf("\tData reason:      [IEC61850_DATA_CHANGE]\n");
				}
				if (ptLogEntries->logEntries[i].logEntryData[j].reasconCode == IEC61850_QUALITY_CHANGE)
				{
					printf("\tData reason:      [IEC61850_DATA_CHANGE]\n");
				}
				if (ptLogEntries->logEntries[i].logEntryData[j].reasconCode == IEC61850_QUALITY_CHANGE)
				{
					printf("\tData reason:      [IEC61850_DATA_CHANGE]\n");
				}
				if (ptLogEntries->logEntries[i].logEntryData[j].reasconCode == IEC61850_DATA_UPDATE)
				{
					printf("\tData reason:      [IEC61850_DATA_CHANGE]\n");
				}
				if (ptLogEntries->logEntries[i].logEntryData[j].reasconCode == IEC61850_INTEGRITY)
				{
					printf("\tData reason:      [IEC61850_DATA_CHANGE]\n");
				}
			}
		}
		if (ptLogEntries->bMoreFollows)
		{
			printf("More Follows\n");
		}
	}
}
void printLogStatus(struct IEC61850_LogStatus* ptResultList)
{
	if (ptResultList != NULL)
	{
		printf("\tOld Entry:%llu\n", ptResultList->OldestEntry);
		printf("\tNew Entry:%llu\n", ptResultList->NewestEntry);
		printf("\tOld EntryTime:");
		printTimeStamp(&ptResultList->OldestEntryTime);
		printf("\n\tNew EntryTime:");
		printTimeStamp(&ptResultList->NewestEntryTime);
		printf("\n");
	}
}

void printDAVal(struct IEC61850_DataAttributeData* ptDataAttribute, int level)
{
	char formateSpace[256] = { 0 };
	for (int i = 0; i < level; i++)
	{
		strcat(formateSpace, "  ");
	}
	if (ptDataAttribute->pvData != NULL)
	{
		switch (ptDataAttribute->ucType)
		{
		case IEC61850_DATATYPE_BOOLEAN:
			if (*((Boolean*)ptDataAttribute->pvData))
			{
				printf("%sBOOLEAN:TRUE\n", formateSpace);
			}
			else
			{
				printf("%sBOOLEAN:FALSE\n", formateSpace);
			}
			break;
		case IEC61850_DATATYPE_INT8:
			printf("%sINT8:%d\n", formateSpace, *((Integer8*)ptDataAttribute->pvData));
			break;
		case IEC61850_DATATYPE_INT8U:
			printf("%sINT8U:%d\n", formateSpace, *((Unsigned8*)ptDataAttribute->pvData));
			break;
		case IEC61850_DATATYPE_INT16:
			printf("%sINT16:%d\n", formateSpace, *((Integer16*)ptDataAttribute->pvData));
			break;
		case IEC61850_DATATYPE_INT16U:
			printf("%sINT16U:%u\n", formateSpace, *((Unsigned16*)ptDataAttribute->pvData));
			break;
		case IEC61850_DATATYPE_INT32:
			printf("%sINT32:%d\n", formateSpace, *((Integer32*)ptDataAttribute->pvData));
			break;
		case IEC61850_DATATYPE_INT32U:
			printf("%sINT32U:%u\n", formateSpace, *((Unsigned32*)ptDataAttribute->pvData));
			break;
		case IEC61850_DATATYPE_INT64:
			printf("%sINT64:%lld\n", formateSpace, *((Integer64*)ptDataAttribute->pvData));
			break;
		case IEC61850_DATATYPE_FLOAT32:
			printf("%sFLOAT32:%f\n", formateSpace, *((Float32*)ptDataAttribute->pvData));
			break;
		case IEC61850_DATATYPE_FLOAT64:
			printf("%sFLOAT64:%f\n", formateSpace, *((Float64*)ptDataAttribute->pvData));
			break;
		case IEC61850_DATATYPE_OCTEL_STRING:
			printf("%sOCTEL_STRING:%s\n", formateSpace, ((char*)ptDataAttribute->pvData));
			break;
		case IEC61850_DATATYPE_VISIBLE_STRING:
			printf("%sVISIBLE_STRING:%s\n", formateSpace, ((char*)ptDataAttribute->pvData));
			break;
		case IEC61850_DATATYPE_UNICODE_STRING:
			printf("%sUNICODE_STRING:%s\n", formateSpace, ((char*)ptDataAttribute->pvData));
			break;
		case IEC61850_DATATYPE_TIMESTAMP:
		{
			printf("%s%s", formateSpace, "TIMESTAMP:");
			printTimeStamp((struct IEC61850_TimeStamp*)ptDataAttribute->pvData);
			printf("\n");
			break;
		}
		case IEC61850_DATATYPE_QUALITY:
		case IEC61850_DATATYPE_CODED_ENUM:
		case IEC61850_DATATYPE_ENUMERATED:
		{
			char* bitString = (char*)calloc(ptDataAttribute->uiBitLength + 1, sizeof(char));
			if (bitString != NULL)
			{
				unsigned int uiByteSize = (ptDataAttribute->uiBitLength + 7) / 8;
				unsigned int uiCount = 0;
				char* pDatas = (char*)(ptDataAttribute->pvData);
				for (unsigned int uiByteIndex = 0; uiByteIndex < uiByteSize && uiCount < ptDataAttribute->uiBitLength; uiByteIndex++)
				{
					for (unsigned int uiBitIndex = 0; uiBitIndex < 8 && uiCount < ptDataAttribute->uiBitLength; uiBitIndex++)
					{
						bitString[uiCount] = pDatas[uiByteIndex] << uiBitIndex;
						if ((0x80 & bitString[uiCount]) == 0x80)
						{
							bitString[uiCount] = '1';
						}
						else
						{
							bitString[uiCount] = '0';
						}
						uiCount++;
					}
				}
				if (ptDataAttribute->ucType == IEC61850_DATATYPE_QUALITY)
				{
					printf("%sQUALITY:%s\n", formateSpace, bitString);
				}
				else if (ptDataAttribute->ucType == IEC61850_DATATYPE_CODED_ENUM)
				{
					printf("%sCODED_ENUM:%s\n", formateSpace, bitString);
				}
				else
				{
					printf("%sENUMERATED:%s\n", formateSpace, bitString);
				}
				free(bitString);
			}
			break;
		}
		case IEC61850_DATATYPE_ARRAY:
		case IEC61850_DATATYPE_STRUCTURE:
		{
			unsigned int uiIndex = 0;
			if (ptDataAttribute->ucType == IEC61850_DATATYPE_ARRAY)
			{
				printf("%sArray:%u\n", formateSpace, ptDataAttribute->uiBitLength);
			}
			else
			{
				printf("%sStruct:%u\n", formateSpace, ptDataAttribute->uiBitLength);
			}
			for (uiIndex = 0; uiIndex < ptDataAttribute->uiBitLength; uiIndex++)
			{
				printDAVal(&((struct IEC61850_DataAttributeData*)ptDataAttribute->pvData)[uiIndex], level + 1);
			}
		}
		}
	}
}